package uiController;

import java.io.IOException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker.State;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import service.SiloService;
import data.NameConstants;
import data.Silo;
import data.SiloAdress;
import data.SiloState;

public class UIContentController implements Initializable {

	@FXML
	private TableView<Silo> mainTable;

	@FXML
	private TableColumn<Silo, String> columnSiloName;

	@FXML
	private TableColumn<Silo, SiloState> columnSiloSate;

	@FXML
	private TableColumn<Silo, String> columnSiloController;

	@FXML
	private Label lblMinFilling;

	@FXML
	private Button btnRefresh;

	@FXML
	private BarChart<String, Number> mainChart;

	@FXML
	private Label lblLastUpdate;

	@FXML
	private SplitPane mainSpiltePane;

	@FXML
	private Label lblMaxFilling;

	@FXML
	private Label lblCurrentFilling;

	@FXML
	private Button AutoRefresh;

	private SiloService siloService = new SiloService();

	@SuppressWarnings("unused")
	private DecimalFormat decimalFormat = new DecimalFormat("#0.000");
	private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

	@FXML
	void btnAutoRefreshClick(ActionEvent event) {
		// Stops the Scheduler
		if (this.btnRefresh.isDisable()) {
			this.btnRefresh.setDisable(false);
			siloService.cancel();
			this.AutoRefresh.setText(NameConstants.START_AUTO_REFRESH);
			// Starts the Scheduler again
		} else {
			this.btnRefresh.setDisable(true);
			this.AutoRefresh.setText(NameConstants.STOP_AUTO_REFRESH);
			startScheduler();
		}

	}

	@FXML
	void btnRefreshClick(ActionEvent event) {
		siloService.start();
		siloService.cancel();
		//
		// ArrayList<Silo> tmp = new ArrayList<Silo>();
		// Silo test = null;
		// for (int i = 0; i < 10; i++) {
		// test = new Silo("Tobias", (double) 0, (double) 30, "cm",
		// new HTTPSiloAdapter("192.168.0.1", "5555"));
		// test.setCurrent((double) 29);
		// tmp.add(test);
		//
		// test = new Silo("Tobias", (double) 0, (double) 30, "cm",
		// new HTTPSiloAdapter("192.168.0.1", "5555"));
		// test.setState(SiloState.ERROR);
		// test.setCurrent((double) 10);
		// tmp.add(test);
		//
		// test = new Silo("Tobias", (double) 0, (double) 30, "cm",
		// new HTTPSiloAdapter("192.168.0.1", "5555"));
		// test.setCurrent((double) 12);
		// tmp.add(test);
		// }
		//
		// this.updateMainTable(tmp);

	}

	private void configureMainTable() {
		this.mainChart.setLegendVisible(false);
		this.mainTable.setEditable(false);

		this.columnSiloName
				.setCellValueFactory(new PropertyValueFactory<Silo, String>(
						"name"));
		this.columnSiloSate
				.setCellValueFactory(new PropertyValueFactory<Silo, SiloState>(
						"state"));
		this.columnSiloController
				.setCellValueFactory(new PropertyValueFactory<Silo, String>(
						"siloControllerAdress"));
		this.mainTable.getSelectionModel().setSelectionMode(
				SelectionMode.SINGLE);
		this.mainTable.setOnMouseClicked(new EventHandler<MouseEvent>() {

			@Override
			public void handle(MouseEvent event) {
				if (mainTable.getSelectionModel().getSelectedItems().size() > 0) {
					Silo silo = mainTable.getSelectionModel()
							.getSelectedItems().get(0);
					updateInfoField(silo);
				}
			}
		});

		this.mainTable
				.setRowFactory(new Callback<TableView<Silo>, TableRow<Silo>>() {
					@Override
					public TableRow<Silo> call(TableView<Silo> param) {
						final TableRow<Silo> row = new TableRow<Silo>() {
							@Override
							protected void updateItem(Silo silo, boolean empty) {
								super.updateItem(silo, empty);
								if (silo != null) {
									if (silo.getState().equals(SiloState.ERROR)) {
										setBackground(new Background(
												new BackgroundFill(
														Color.TOMATO,
														new CornerRadii(0),
														Insets.EMPTY)));

									} else if (!silo.getState().equals(
											SiloState.ERROR)
											&& silo.getFilling() > (double) 90) {
										setBackground(new Background(
												new BackgroundFill(
														Color.DARKORANGE,
														new CornerRadii(0),
														Insets.EMPTY)));

									} else if (silo.getState().equals(
											SiloState.HIGH)) {
										setBackground(new Background(
												new BackgroundFill(
														Color.TOMATO,
														new CornerRadii(0),
														Insets.EMPTY)));

									} else {
										setBackground(new Background(
												new BackgroundFill(
														Color.LIMEGREEN,
														new CornerRadii(0),
														Insets.EMPTY)));
									}

								}

							}

						};
						return row;
					}
				});
	}

	private void updateMainTable(ArrayList<Silo> result) {
		ObservableList<Silo> tmp = FXCollections.observableArrayList();
		tmp.addAll(result);
		this.mainTable.setItems(tmp);
		this.lblLastUpdate.setText(NameConstants.LAST_UPDATE
				+ dateFormat.format(Calendar.getInstance().getTime()));

	}

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		configureMainTable();
		configureSiloService();
	}

	public void start(ArrayList<SiloAdress> adresses) throws IOException {
		for (SiloAdress siloAdress : adresses) {
			this.siloService.createSiloAdapter(siloAdress.getiNetAdress(),
					siloAdress.getPort());
		}
		this.btnRefresh.setDisable(true);
		this.siloService.requestInitialSiloData();
		startScheduler();
	}

	private void configureSiloService() {
		siloService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

			@Override
			public void handle(WorkerStateEvent event) {

				@SuppressWarnings("unchecked")
				ArrayList<Silo> result = (ArrayList<Silo>) event.getSource()
						.getValue();
				updateMainTable(result);
				// TODO: UpdateInfoField
			}

		});

	}

	private void updateInfoField(Silo silo) {
		this.mainChart.getData().clear();
		Series<String, Number> aSeries = new Series<String, Number>();
		aSeries.getData().add(
				new Data<String, Number>(NameConstants.FILLING, silo
						.getFilling()));
		this.mainChart.getData().add(aSeries);

		lblCurrentFilling.setText(NameConstants.CURRENT + silo.getCurrent());
		lblMaxFilling.setText(NameConstants.MAX + silo.getMax());
		lblMinFilling.setText(NameConstants.MIN + silo.getMin());
	}

	private void startScheduler() {
		if (!siloService.getState().equals(State.SCHEDULED)
				|| siloService.getState().equals(State.RUNNING)) {
			siloService.start();
		}
	}

}
